home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / xlib03.zip / XRLETOOL.ASM < prev    next >
Assembly Source File  |  1993-04-05  |  18KB  |  658 lines

  1. ;-----------------------------------------------------------------------
  2. ; MODULE XRLETOOL
  3. ;
  4. ; Hardware detection module
  5. ;
  6. ; Compile with Tasm.
  7. ; C callable.
  8. ;
  9. ;
  10. ; ****** XLIB - Mode X graphics library                ****************
  11. ; ******                                               ****************
  12. ; ****** Written By Themie Gouthas                     ****************
  13. ; ****** Aeronautical Research Laboratory              ****************
  14. ; ****** Defence Science and Technology Organisation   ****************
  15. ; ****** Australia                                     ****************
  16. ;
  17. ; egg@dstos3.dsto.gov.au
  18. ; teg@bart.dsto.gov.au
  19. ;-----------------------------------------------------------------------
  20.  
  21. COMMENT $
  22.  
  23. Firstly, please note that this module has been built from the ground up
  24. in a rush so although I'm confident all the functions work, I have'nt
  25. extensively checked them. If any should surface please let me know.
  26.  
  27.  
  28. This module implements a number of functions comprising an RLE encoding
  29. decoding system.
  30.  
  31. RLE stands for RUN LENGTH ENCODING. It is a quick simple data compression
  32. scheme which is commonly used for image data compression or compression
  33. of any data. Although not the most efficient system, it is fast, which is
  34. why it is used in image storage systems like PCX. This implementation is
  35. more efficient than the one used in PCX files because it uses 1 bit to
  36. identify a Run Length byte as opposed to two in PCX files, but more on this
  37. later.
  38.  
  39. This set of functions can be used to implement your own compressed image
  40. file format or for example compress game mapse for various levels etc.
  41. The uses are limited by your imagination.
  42.  
  43. I opted for trading off PCX RLE compatibility for the improved compression
  44. efficiency.
  45.  
  46. Here is how the data is un-compressed to give an idea of its structure.
  47.  
  48.  
  49. STEP 1 read a byte from the RLE compressed source buffer.
  50.  
  51. STEP 2 if has its high bit then the lower 7 bits represent the number of
  52.        times the next byte is to be repeated in the destination buffer.
  53.        if the count (lower 7 bits) is zero then
  54.       we have finished decoding goto STEP 5
  55.        else goto STEP 4
  56.  
  57. STEP 3 Read a data from the source buffer and copy it directly to the
  58.        destination buffer.
  59.        goto STEP 1
  60.  
  61. STEP 4 Read a data from the source buffer and copy it to the destination
  62.        buffer the number of times specified by step 2.
  63.        goto STEP 1
  64.  
  65. STEP 5 Stop, decoding done.
  66.  
  67. If the byte does not have the high bit set then the byte itself is transfered
  68.  to the destination buffer.
  69.  
  70. Data bytes that have the high bit already set and are unique in the input
  71.  stream are represented as a Run Length of 1 (ie 81 which includes high bit)
  72.  followed by the data byte.
  73.  
  74. If your original uncompressed data contains few consecutive bytes and most
  75. have high bit set (ie have values > 127) then your so called
  76. compressed data would require up to 2x the space of the uncompressed data,
  77. so be aware that the compression ratio is extremely variable depending on the
  78. type of data being compressed.
  79.  
  80. Apologies for this poor attempt at a description, but you can look up
  81. RLE in any good text. Alternatively, any text that describes the PCX file
  82. structure in any depth should have a section on RLE compression.
  83.  
  84.  
  85.  
  86. $
  87.  
  88. LOCALS
  89. .286
  90.  
  91. include model.inc
  92. include xrletool.inc
  93.  
  94.     .data
  95.  
  96. _RLE_last_buff_offs dw (0)
  97. RLEbuff db 2 dup (?)
  98.  
  99.     .code
  100.  
  101. ;****************************************************************
  102. ;*
  103. ;* NAME: x_buff_RLEncode
  104. ;*
  105. ;*
  106. ;* RLE Compresses a source buffer to a destination buffer and returns
  107. ;* the size of the resultant compressed data.
  108. ;*
  109. ;* C PROTOTYPE:
  110. ;*
  111. ;*  extern unsigned int x_buff_RLEncode(char far * source_buff,
  112. ;*           char far * dest_buff,unsigned int count);
  113. ;*
  114. ;* source_buff   - The buffer to compress
  115. ;* dest_buff     - The destination buffer
  116. ;* count         - The size of the source data in bytes
  117. ;*
  118. ;* WARNING: buffers must be pre allocated.
  119. ;*
  120. proc _x_buff_RLEncode
  121. ARG   src:dword,dest:dword,count:word
  122.     push bp
  123.     mov  bp,sp
  124.     push ds
  125.     push si
  126.     push di
  127.  
  128.     lds  si,[src]
  129.     les  di,[dest]
  130.     mov  dx,[count]
  131.  
  132.     push di
  133.  
  134.     lodsb              ; Load first byte into BL
  135.     mov  bl,al
  136.     xor  cx,cx         ; Set number characters packed to zero
  137.     cld                ; All moves are forward
  138.  
  139. @@RepeatByte:
  140.     lodsb           ; Get byte into AL
  141.     inc  cx            ; Increment compressed byte count
  142.     sub  dx,1          ; Decrement bytes left
  143.     je   @@LastByte    ; Finished when dx = 1
  144.     cmp  cx,7fh        ; Filled block yet
  145.     jne  @@NotFilled   ; Nope!
  146.  
  147.     or   cl,80h        ; Set bit to indicate value is repeat count
  148.     mov  es:[di],cl    ; store it
  149.     inc  di
  150.     xor  cx,cx         ; clear compressed byte count
  151.     mov  es:[di],bl    ; store byte to be repeated
  152.     inc  di
  153.  
  154. @@NotFilled:
  155.     cmp  al,bl         ; hase there been a byte transition ?
  156.     je   @@RepeatByte  ; No!
  157.  
  158.     cmp  cl,1          ; do we have a unique byte ?
  159.     jne  @@NotUnique   ; No
  160.  
  161.     test bl,80h        ; Can this byte be mistaken for repeat count
  162.     jz   @@Unambiguous ; No ! Dont bother with repeat count
  163.  
  164. @@NotUnique:
  165.     or   cl,80h        ; Set bit to indicate value is repeat count
  166.     mov  es:[di],cl    ; store it
  167.     inc  di
  168. @@Unambiguous:
  169.     xor  cx,cx         ; clear compressed byte count
  170.     mov  es:[di],bl    ; store byte to be repeated
  171.     inc  di
  172.     mov  bl,al         ; move latest byte into bl
  173.     jmp  short @@RepeatByte
  174.  
  175. @@LastByte:
  176.     cmp  cl,1          ; Is this a unique byte
  177.     jne  @@FinalCount  ; No
  178.  
  179.     test bl,80h        ; Can this byte be mistaken for repeat count
  180.     jz   @@FinalByte   ; No, so dont bother with the repeat count
  181.  
  182. @@FinalCount:              ; Output the repeat count
  183.     or   cl,80h
  184.     mov  al,cl
  185.     stosb
  186.  
  187. @@FinalByte:
  188.     mov  al,bl
  189.     stosb
  190.  
  191.     mov  al,80h       ; store terminating null length
  192.     stosb
  193.  
  194.         ; Calculate encoded length of buffer
  195.  
  196.     mov  ax,di
  197.     pop  di
  198.     sub  ax,di
  199.  
  200.     pop  di
  201.     pop  si
  202.     pop  ds
  203.     pop  bp
  204.     ret
  205. _x_buff_RLEncode endp
  206.  
  207.  
  208.  
  209. ;****************************************************************
  210. ;*
  211. ;* NAME: x_buff_RLE_size
  212. ;*
  213. ;*
  214. ;* Returns the size the input data would compress to.
  215. ;*
  216. ;* C PROTOTYPE:
  217. ;*
  218. ;*  extern unsigned int x_buff_RLE_size(char far * source_buff,
  219. ;*           unsigned int count);
  220. ;*
  221. ;* source_buff   - The uncompressed data buffer
  222. ;* count         - The size of the source data in bytes
  223. ;*
  224. ;*
  225. proc _x_buff_RLE_size
  226. ARG   src:dword,count:word
  227.     push bp
  228.     mov  bp,sp
  229.     push ds
  230.     push si
  231.     push di
  232.  
  233.     lds  si,[src]
  234.     mov  dx,[count]
  235.  
  236.     xor  di,di
  237.  
  238.     lodsb              ; Load first byte into BL
  239.     mov  bl,al
  240.     xor  cx,cx         ; Set number characters packed to zero
  241.     cld                ; All moves are forward
  242.  
  243. @@RepeatByte:
  244.     lodsb           ; Get byte into AL
  245.     inc  cx            ; Increment compressed byte count
  246.     sub  dx,1          ; Decrement bytes left
  247.     je   @@LastByte    ; Finished when dx = 1
  248.     cmp  cx,7fh        ; Filled block yet
  249.     jne  @@NotFilled   ; Nope!
  250.  
  251.     add  di,2          ; RL/BYTE pair stub
  252.  
  253. @@NotFilled:
  254.     cmp  al,bl         ; hase there been a byte transition ?
  255.     je   @@RepeatByte  ; No!
  256.  
  257.     cmp  cl,1          ; do we have a unique byte ?
  258.     jne  @@NotUnique   ; No
  259.  
  260.     test bl,80h        ; Can this byte be mistaken for repeat count
  261.     jz   @@Unambiguous ; No ! Dont bother with repeat count
  262.  
  263. @@NotUnique:
  264.     inc  di            ; RL stub
  265.  
  266. @@Unambiguous:
  267.     xor  cx,cx         ; clear compressed byte count
  268.     inc  di            ; BYTE stub
  269.     mov  bl,al         ; move latest byte into bl
  270.     jmp  short @@RepeatByte
  271.  
  272. @@LastByte:
  273.     cmp  cl,1          ; Is this a unique byte
  274.     jne  @@FinalCount  ; No
  275.  
  276.     test bl,80h        ; Can this byte be mistaken for repeat count
  277.     jz   @@FinalByte   ; No, so dont bother with the repeat count
  278.  
  279. @@FinalCount:              ; Output the repeat count
  280.     inc  di            ; RL stub
  281.  
  282. @@FinalByte:
  283.     inc  di            ; BYTE stub
  284.     inc  di            ; RL stub - Account for termiating null
  285.     mov  ax,di
  286.  
  287.     pop  di
  288.     pop  si
  289.     pop  ds
  290.     pop  bp
  291.     ret
  292. _x_buff_RLE_size endp
  293.  
  294. ;****************************************************************
  295. ;*
  296. ;* NAME: x_buff_RLDecode
  297. ;*
  298. ;*
  299. ;* Expands an RLE compresses source buffer to a destination buffer.
  300. ;* returns the size of the resultant uncompressed data.
  301. ;*
  302. ;* C PROTOTYPE:
  303. ;*
  304. ;*  extern unsigned int x_buff_RLDecode(char far * source_buff,
  305. ;*           char far * dest_buff);
  306. ;*
  307. ;* source_buff   - The buffer to compress
  308. ;* dest_buff     - The destination buffer
  309. ;*
  310. ;* WARNING: buffers must be pre allocated.
  311. ;*
  312. proc _x_buff_RLDecode
  313. ARG   src:dword,dest:dword
  314. LOCAL si_ini:word=LocalStk
  315.     push bp
  316.     mov  bp,sp
  317.         sub  sp,LocalStk
  318.     push ds
  319.     push si
  320.     push di
  321.  
  322.     mov  dx,-1        ; zero output data buffer size - 1 (compensate for
  323.               ; terminating null RL)
  324.     xor  cx,cx        ; clear CX
  325.     cld               ; Move forward
  326.  
  327.     lds  si,[src]     ; point ds:si -> RLE source
  328.     les  di,[dest]    ; point es:di -> uncompressed buffer
  329.         mov  [si_ini],si
  330.  
  331. @@UnpackLoop:
  332.     lodsb             ; load a byte into AL
  333.     cmp  al,80h       ; is it terminating null RL code
  334.     je   @@done       ; if so jump
  335.  
  336.     test al,80h       ; is AL a RL code (is high bit set ?)
  337.     jz   @@NoRepeats  ; if not the no RL encoding for this byte, jump
  338.  
  339.     mov  cl,al        ; set CL to RL (run length) taking care
  340.     xor  cl,80h       ; to remove the bit identifying it as a RL
  341.         add  dx,cx        ; increment buffer size
  342.  
  343.     lodsb             ; get the next byte which should be a data byte
  344.  
  345.     shr  cx,1         ; divide RL by 2 to use word stos
  346.     jcxz @@NoRepeats  ; result is zero, jump
  347.  
  348.     mov  ah,al        ; copy data byte to AH since going to use stosw
  349.     rep  stosw        ; copy AX to outbut buffer RL times
  350.     jnb  @@UnpackLoop ; when we shifted the RL if we had a carry =>
  351.               ; we had an odd number of repeats so store the
  352.               ; last BYTE if carry was set otherwise jump
  353.         stosb             ; store AL in destination buffer
  354.         jmp  short @@UnpackLoop
  355.  
  356. @@NoRepeats:
  357.     inc  dx           ; increment buffer size
  358.     stosb             ; store AL in destination buffer
  359.         jmp  short @@UnpackLoop
  360.  
  361. @@done:
  362.  
  363.         mov  bx,si
  364.         sub  bx,[si_ini]
  365.     mov  ax,dx
  366.     pop  di
  367.     pop  si
  368.     pop  ds
  369.         mov  [_RLE_last_buff_offs],bx
  370.         mov  sp,bp
  371.     pop  bp
  372.     ret
  373. _x_buff_RLDecode endp
  374.  
  375. ;==========================================================================
  376. ;==========================================================================
  377. ; RLEncode to file / RLDecode from file
  378. ; WARNING the following functions are *MUCH* slower than the above
  379. ; Its best to use the above functions with intermediate buffers where
  380. ; disk i/o is concearned... See demo 4
  381. ;==========================================================================
  382. ;==========================================================================
  383.  
  384. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  385. ;
  386. ; put_cx
  387. ;
  388. ;   Local utility proc for x_file_RLEncode - write cx to file
  389. ;
  390. ; Entry:
  391. ;       es:dx -> output buffer
  392. ;       cx = word to write
  393. ;
  394. ;
  395. put_cx proc near
  396.     push ds             ; preserve critical registers
  397.     push ax
  398.     push bx
  399.     mov  ax,ds          ; set up DS to output buffers segment
  400.     mov  ds,ax
  401.     mov  word ptr [RLEbuff],cx ; copy CX to output buffer
  402.     mov  ah,40h         ; select "write to file or device" DOS service
  403.     mov  bx,[handle]    ; select handle of file to write
  404.     mov  cx,2           ; sending 2 bytes
  405.     int  21h        ; call DOS service
  406.     pop  bx             ; recover registers
  407.     pop  ax
  408.     pop  ds
  409.     ret
  410. put_cx endp
  411.  
  412. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  413. ;
  414. ; put_cx
  415. ;
  416. ;   Local utility proc for x_file_RLEncode - write cx to file
  417. ;
  418. ; Entry:
  419. ;       es:dx -> output buffer
  420. ;       cx = word to write
  421. ;
  422. ;
  423. put_cl proc near
  424.     push ds             ; preserve critical registers
  425.     push ax
  426.     push bx
  427.     mov  ax,ds          ; set up DS to output buffers segment
  428.     mov  ds,ax
  429.     mov  byte ptr [RLEbuff],cl
  430.     mov  ah,40h         ; select "write to file or device" DOS service
  431.     mov  bx,[handle]    ; select handle of file to write
  432.     mov  cx,1           ; sending 1 byte
  433.     int  21h        ; call DOS service
  434.     pop  bx             ; recover registers
  435.     pop  ax
  436.     pop  ds
  437.     ret
  438. put_cl endp
  439.  
  440.  
  441. ;****************************************************************
  442. ;*
  443. ;* NAME: x_file_RLEncode
  444. ;*
  445. ;*
  446. ;* RLE Compresses a source buffer to an output file returning
  447. ;* the size of the resultant compressed data or 0 if it fails.
  448. ;*
  449. ;* C PROTOTYPE:
  450. ;*
  451. ;*  extern unsigned int x_file_RLEncode(int handle,
  452. ;*           char far * source_buff,unsigned int count);
  453. ;*
  454. ;* source_buff   - The buffer to compress
  455. ;* handle        - The file handler
  456. ;* count         - The size of the source data in bytes
  457. ;*
  458. ;*
  459. proc _x_file_RLEncode
  460. ARG   handle:word,src:dword,count:word
  461. LOCAL filesize:word=LocalStk
  462.     push bp
  463.     mov  bp,sp
  464.     sub  sp,LocalStk
  465.     push ds
  466.     push si
  467.     push di
  468.  
  469.     mov  [filesize],0
  470.     mov  dx,offset [RLEbuff]
  471.     mov  ax,ds
  472.     mov  es,ax
  473.     lds  si,[src]
  474.     mov  di,[count]
  475.  
  476.     lodsb              ; Load first byte into BL
  477.     mov  bl,al
  478.     xor  cx,cx         ; Set number characters packed to zero
  479.     cld                ; All moves are forward
  480.  
  481. @@RepeatByte:
  482.     lodsb           ; Get byte into AL
  483.     inc  cx            ; Increment compressed byte count
  484.     sub  di,1          ; Decrement bytes left
  485.     je   @@LastByte    ; Finished when di = 1
  486.     cmp  cx,7fh        ; Filled block yet
  487.     jne  @@NotFilled   ; Nope!
  488.  
  489.     or   cl,80h        ; Set bit to indicate value is repeat count
  490.     mov  ch,bl
  491.     add  [filesize],2
  492.     call put_cx
  493.     jb   @@FileError   ; if carry set then file I/O error
  494.     xor  cx,cx         ; clear compressed byte count
  495.  
  496. @@NotFilled:
  497.     cmp  al,bl         ; hase there been a byte transition ?
  498.     je   @@RepeatByte  ; No!
  499.  
  500.     cmp  cl,1          ; do we have a unique byte ?
  501.     jne  @@NotUnique   ; No
  502.  
  503.     test bl,80h        ; Can this byte be mistaken for repeat count
  504.     jz   @@Unambiguous ; No ! Dont bother with repeat count
  505.  
  506. @@NotUnique:
  507.     or   cl,80h        ; Set bit to indicate value is repeat count
  508.     inc  [filesize]
  509.     call put_cl        ; store it
  510.         jb   @@FileError   ; if carry set then file I/O error
  511. @@Unambiguous:
  512.  
  513.     mov  cl,bl         ; store byte to be repeated
  514.         inc  [filesize]
  515.     call put_cl
  516.         jb   @@FileError   ; if carry set then file I/O error
  517.     mov  bl,al         ; move latest byte into bl
  518.         xor  cx,cx         ; clear compressed byte count
  519.     jmp  short @@RepeatByte
  520.  
  521. @@FileError:
  522.     mov  ax,0
  523.     jmp  short @@exit
  524.  
  525. @@LastByte:
  526.     cmp  cl,1          ; Is this a unique byte
  527.     jne  @@FinalCount  ; No
  528.  
  529.     test bl,80h        ; Can this byte be mistaken for repeat count
  530.     jz   @@FinalByte   ; No, so dont bother with the repeat count
  531.  
  532. @@FinalCount:              ; Output the repeat count
  533.     or   cl,80h
  534.         inc  [filesize]
  535.     call put_cl
  536.     jb   @@FileError   ; if carry set then file I/O error
  537.  
  538. @@FinalByte:
  539.     mov  cl,bl
  540.     mov  ch,80h
  541.     add  [filesize],2
  542.     call put_cx        ; store terminating null length
  543.     jb   @@FileError   ; if carry set then file I/O error
  544.  
  545.     mov  ax,[filesize]
  546.     jmp  short @@exit
  547.  
  548. @@exit:
  549.     pop  di
  550.     pop  si
  551.     pop  ds
  552.     mov  sp,bp
  553.     pop  bp
  554.     ret
  555. _x_file_RLEncode endp
  556.  
  557.  
  558.  
  559.  
  560. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  561. ;
  562. ; GET_BYTE
  563. ;
  564. ;   macro to read a byte from the input file into al
  565. ;
  566. GET_BYTE macro
  567.     push bx
  568.     mov  ah,3fh         ; select "read from file or device" DOS service
  569.     mov  bx,[handle]    ; Select handle of file to close
  570.     mov  cx,1           ; Want to read 1 byte
  571.     int  21h            ; call DOS service
  572.     pop  bx
  573.     jb   @@FileError    ; failed if carry flag set
  574.     mov  al,[RLEbuff]
  575.     endm
  576.  
  577.  
  578. ;****************************************************************
  579. ;*
  580. ;* NAME: x_file_RLDecode
  581. ;*
  582. ;*
  583. ;* Expands an RLE compresses file to a destination RAM buffer.
  584. ;* returns the size of the resultant uncompressed data.
  585. ;*
  586. ;* C PROTOTYPE:
  587. ;*
  588. ;*  extern unsigned int x_buff_RLDecode(int handle,
  589. ;*           char far * dest_buff);
  590. ;*
  591. ;* handle        - Input file handle
  592. ;* dest_buff     - The destination buffer
  593. ;*
  594. ;*
  595. proc _x_file_RLDecode
  596. ARG   handle:word,dest:dword
  597.     push bp
  598.     mov  bp,sp
  599.     push si
  600.     push di
  601.  
  602.  
  603.     mov  bx,-1        ; zero output data buffer size - 1 (compensate for
  604.               ; terminating null RL)
  605.     mov  dx,offset [RLEbuff] ; setup DS:DX -> RLEBuffer
  606.         xor  cx,cx        ; clear CX
  607.     cld               ; Move forward
  608.  
  609.     les  di,[dest]    ; point es:di -> uncompressed buffer
  610.  
  611. @@UnpackLoop:
  612.  
  613.     GET_BYTE      ; Load a byte from file into AL
  614.  
  615.     cmp  al,80h       ; is it terminating null RL code
  616.     je   @@done       ; if so jump
  617.  
  618.     test al,80h       ; is AL a RL code (is high bit set ?)
  619.     jz   @@NoRepeats  ; if not the no RL encoding for this byte, jump
  620.  
  621.     mov  cl,al        ; set CL to RL (run length) taking care
  622.     xor  cl,80h       ; to remove the bit identifying it as a RL
  623.     add  bx,cx        ; increment buffer size
  624.     mov  si,cx        ; save the CX value
  625.     GET_BYTE          ; Load a byte from file into AL
  626.     mov  cx,si        ; restore CX value
  627.         shr  cx,1         ; divide RL by 2 to use word stos
  628.     jcxz @@NoRepeats  ; result is zero, jump
  629.  
  630.     mov  ah,al        ; copy data byte to AH since going to use stosw
  631.     rep  stosw        ; copy AX to outbut buffer RL times
  632.     jnb  @@UnpackLoop ; when we shifted the RL if we had a carry =>
  633.               ; we had an odd number of repeats so store the
  634.               ; last BYTE if carry was set otherwise jump
  635.         stosb             ; store AL in destination buffer
  636.         jmp  short @@UnpackLoop
  637.  
  638. @@NoRepeats:
  639.     inc  bx
  640.     stosb             ; store AL in destination buffer
  641.         jmp  short @@UnpackLoop
  642.  
  643. @@FileError:
  644.     mov  ax,0
  645.     jmp  short @@exit
  646.  
  647. @@done:
  648.     mov  ax,bx
  649. @@exit:
  650.     pop  di
  651.     pop  si
  652.     pop  bp
  653.     ret
  654. _x_file_RLDecode endp
  655.  
  656.     end
  657.  
  658.